/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package SecretSanta.core;
import java.util.Calendar;
import java.util.ArrayList;
import java.util.List;
import SecretSanta.service.*;
import SecretSanta.service.impl.*;
import java.util.Random;

/**
 *
 * @author mrandell
 */
public class SecretSantaCore 
{
    public Boolean sendEmails()
    {
        Boolean ret = true;
        HistoryMap history = this.getLatestHistory();
        List<Person> participants = this.getPeople((this.getLatestHistory().getAllSantaNames()));
        
        for(int i = 0, j = participants.size(); i < j; i++)
        {
            Person person = participants.get(i);
            String email = person.getEmail();
            String santa = person.getName();
            String reciever = history.getReciever(santa);
            ret = ret & mail.send(email, santa, reciever, year);
        }
        return ret;
    }
    
    public Boolean sendEmail(String name)
    {
        HistoryMap history = this.getLatestHistory();
        Person p = this.getPerson(name);
        String email = p.getEmail();
        String santa = p.getName();
        String reciever = history.getReciever(santa);
        
        return mail.send(email, santa, reciever, year);
    }
    
    public Boolean generateMappingAndSend(List<Person> participants, boolean restrict_pairs)
    {
        return this.generateMapping(participants, restrict_pairs) & this.sendEmails();
               
    }
    
    public Boolean generateMapping(List<Person> participants, boolean restrict_pairs)
    {
        Boolean ret = true;
        ret = ret & parser.updatePeople(participants);
        
        //Add last years recievers to the restrictions if its chose not to include them
        if(restrict_pairs)
        {
            HistoryMap last = null;
            List<HistoryMap> last_list = parser.getHistory(year-1, year-1);
            if(last_list != null)
            {
                last = last_list.get(0);
                for(Person person : participants)
                {
                    person.addRestriction(last.getReciever(person.getName()));
                }
            }
        }
        
        HistoryMap map = this.setupMapping(participants);
        
        if(map == null)
        {
        System.out.println("___________NULL_______________");
            return false;
        }
        
        System.out.println("__________________________");
        List<Pair> people = map.getMappings();
        for(Pair mapping: people)
        {
            System.out.println(mapping.getSanta());
            System.out.println("\t" + mapping.getReciever());
        }
        System.out.println("__________________________");
        
        
        ret = ret & parser.addHistoryMap(map);
        return ret;
    }
    
    public Person getPerson(String name)
    {
        return parser.getPerson(name);
    }
    
    public List<Person> getPeople(List<String> names)
    {
        if (names == null)
        {
            return null;
        }
        return parser.getPeople(names);
    }
    
    public Boolean updatePerson(Person person)
    {
        ArrayList<Person> people = new ArrayList();
        people.add(person);
        return this.updatePeople(people);
    }
    
    public Boolean updatePeople(List<Person> participants)
    {
        return parser.updatePeople(participants);
    }
    
    public List<HistoryMap> getHistoryRange(int start, int end)
    {
        List<HistoryMap> history = parser.getHistory(start, end);
        if(history.isEmpty())
        {
            return null;
        }
        else
        {
            return history;
        }
    }
    
    public HistoryMap getLatestHistory()
    {
        HistoryMap history =  parser.getLatestHistory();
        if(history == null)
        {
            return null;
        }
        else
        {
            return history;
        }
    }
    
    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public SecretSantaCore(int year) {
        this.year = year;
        mail = new MailClientImpl();
        parser = new SantaParserJaxbImpl();
    }
    
    public SecretSantaCore(){
        Calendar toDay = Calendar.getInstance();
        year = toDay.get(Calendar.YEAR);
        mail = new MailClientImpl();
        parser = new SantaParserJaxbImpl();
    }
    
    private HistoryMap setupMapping(List<Person> participants)
    {
        //For each participant, choose their match, log the pairing and remove the name from the pool
        //If a match cannot be found after running 100 times, give up
        HistoryMap new_map = null;
        for(int i = 0; i < 100; i++)
        {
            //initialize a new HistoryMap to story the mapping
            new_map = new HistoryMap(year);
            //Create a list of just names that have yet to be assigned
            ArrayList<String> pool = new ArrayList();
            for(Person participant: participants)
            {
                pool.add(participant.getName());
            }
            //run through participants and randomly select a match
            for(Person participant: participants)//int x = 0, y = participants.size(); x < y; i++)
            {
                String santa = participant.getName();
                String reciever = this.selectValidRandom(participant, pool);
                if(reciever == null)
                {
                    new_map = null;
                    break;
                }
                pool.remove(reciever);
                new_map.addPairing(new Pair(santa, reciever));                
            }
            if(new_map != null)
            {
                return new_map;
            }
        }
        return new_map;
    }
    
    private String selectValidRandom(Person santa, List<String> pool)
    {
        List<String> restrictions = santa.getRestrictions();
        //Create a list of only valid names
        ArrayList<String> valid_pool = new ArrayList();
        for(String person : pool)
        {
            valid_pool.add(person);
        }
        valid_pool.remove(santa.getName());
        for(String person : restrictions)
        {
            valid_pool.remove(person);
        }
        //return null if no valid names
        if(valid_pool.size() <= 0)
        {
            return null;
        }
        
        Random randomGenerator = new Random();
        int randomInt = randomGenerator.nextInt(valid_pool.size());
        System.out.println(valid_pool.get(randomInt) + "############" + randomInt);
        
        return valid_pool.get(randomInt);
    }
    
    int year;
    MailClient mail;
    SantaParser parser;
    
}
